﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace QldtSdh.BLL
{
    using DAL;
    using DAL.Models;

    class BizThoiKhoaBieu
    {
        internal static DateTime GetNgayHocDauTien(DAL.Models.LopHocPhan _LopHocPhan, CEMS4UG_DHKHContext db = null)
        {
            if (_LopHocPhan == null)
                return DateTime.Now;

            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetNgayHocDauTien(_LopHocPhan, db2);
            else
            {
                DateTime ngayHoc = DateTime.Now;
                try
                {
                    ngayHoc = db.LopHocPhan_ThoiKhoaBieuDbSet
                        .Where(e => e.MaLopHocPhanGUID == _LopHocPhan.MaLopHocPhanGUID)
                        .Min(e => e.NgayHoc);
                }
                catch (System.InvalidOperationException)
                {
                    ngayHoc = DateTime.Now;
                }
                catch (Exception exc)
                {
                    throw exc;
                }
                return ngayHoc;
            }
        }

        internal static DateTime GetNgayHocCuoiCung(DAL.Models.LopHocPhan _LopHocPhan, CEMS4UG_DHKHContext db = null)
        {
            if (_LopHocPhan == null)
                return DateTime.Now;
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetNgayHocCuoiCung(_LopHocPhan, db2);
            else
            {
                DateTime ngayHoc = DateTime.Now;
                try
                {
                    ngayHoc = db.LopHocPhan_ThoiKhoaBieuDbSet
                        .Where(e => e.MaLopHocPhanGUID == _LopHocPhan.MaLopHocPhanGUID)
                        .Max(e => e.NgayHoc);
                }
                catch (System.InvalidOperationException)
                {
                    ngayHoc = DateTime.Now;
                }
                catch (Exception exc)
                {
                    throw exc;
                }
                return ngayHoc;
            }
        }

        internal static List<LopHocPhan_ThoiKhoaBieu> GetList(LopHocPhan _LopHocPhan, DateTime _ThuHai, DateTime _CN, CEMS4UG_DHKHContext db = null)
        {
            if (_LopHocPhan == null)
                return new List<LopHocPhan_ThoiKhoaBieu>();

            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetList(_LopHocPhan, _ThuHai, _CN, db2);
            else
            {
                _ThuHai = _ThuHai.Date;
                _CN = _CN.Date;
                var maLopHocPhanGUID = _LopHocPhan.MaLopHocPhanGUID;
                var lst = db.LopHocPhan_ThoiKhoaBieuDbSet
                    .Include("GiangVien")
                    .Where(e =>
                        e.MaLopHocPhanGUID == maLopHocPhanGUID &&
                        _ThuHai <= e.NgayHoc && e.NgayHoc <= _CN)
                    .ToList();
                return lst;
            }
        }

        /// <summary>
        /// Thứ Hai/Thứ Ba, ... của ngày trong tuần
        /// </summary>
        /// <param name="dow"></param>
        /// <returns></returns>
        internal static string GetThuTrongTuan(DayOfWeek dow)
        {
            if (dow == DayOfWeek.Monday)
                return "Thứ Hai";
            else if (dow == DayOfWeek.Tuesday)
                return "Thứ Ba";
            else if (dow == DayOfWeek.Wednesday)
                return "Thứ Tư";
            else if (dow == DayOfWeek.Thursday)
                return "Thứ Năm";
            else if (dow == DayOfWeek.Friday)
                return "Thứ Sáu";
            else if (dow == DayOfWeek.Saturday)
                return "Thứ Bảy";
            else
                return "CN";
        }

        /// <summary>
        /// Thứ Hai/Thứ Ba/Thứ Tư/...
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        internal static string GetThuTrongTuan(DateTime date)
        {
            return GetThuTrongTuan(date.DayOfWeek);
        }

        /// <summary>
        /// 2/3/4/5
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        internal static string GetThuTrongTuanOf(DateTime date)
        {
            var x = "";
            switch (date.DayOfWeek)
            {
                case DayOfWeek.Monday: x = "2"; break;
                case DayOfWeek.Tuesday: x = "3"; break;
                case DayOfWeek.Wednesday: x = "4"; break;
                case DayOfWeek.Thursday: x = "5"; break;
                case DayOfWeek.Friday: x = "6"; break;
                case DayOfWeek.Saturday: x = "7"; break;
                case DayOfWeek.Sunday: x = "CN"; break;
            }
            return x;

        }

        /// <summary>
        /// Monday->0, Tuesday->1, ...
        /// </summary>
        /// <param name="dow"></param>
        /// <returns></returns>
        internal static int GetIndexFromDOW(DayOfWeek dow)
        {
            if (dow == DayOfWeek.Monday)
                return 0;
            else if (dow == DayOfWeek.Tuesday)
                return 1;
            else if (dow == DayOfWeek.Wednesday)
                return 2;
            else if (dow == DayOfWeek.Thursday)
                return 3;
            else if (dow == DayOfWeek.Friday)
                return 4;
            else if (dow == DayOfWeek.Saturday)
                return 5;
            else
                return 6;
        }

        /// <summary>
        /// Sáng/Chiều/Tối
        /// </summary>
        /// <param name="buoiIdx"></param>
        /// <returns></returns>
        internal static string GetStringOfBuoi(int buoiIdx)
        {
            if (buoiIdx == 0)
                return "Sáng";
            else if (buoiIdx == 1)
                return "Chiều";
            else
                return "Tối";
        }

        internal static bool GiangVienBan(string maGiangVien, DateTime ngayHoc, int buoiHoc, string ngoaiTruId = null, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GiangVienBan(maGiangVien, ngayHoc, buoiHoc, ngoaiTruId, db2);
            else
            {
                ngayHoc = ngayHoc.Date;

                // Kiểm tra lịch bận giảng dạy SĐH
                int n = db.LopHocPhan_ThoiKhoaBieuDbSet
                    .Where(e => e.MaGiangVien == maGiangVien && e.NgayHoc == ngayHoc && e.BuoiHoc == buoiHoc && e.MaLopHocPhan_ThoiKhoaBieuGUID != ngoaiTruId)
                    .Count();
                if (n > 0)
                    return true;

                // Kiểm tra lịch bận coi thi SĐH?

                // Kiểm tra lịch bận giảng dạy ĐH

                // ------------------------------
                return false;
            }
        }

        internal static bool GiangVienBanGiangDayDaiHoc(string maGiangVien, DateTime ngayHoc, int buoiHoc, CEMS_DHKH.Models.CEMS_DHKhoaHocContext db = null)
        {
            try
            {
                if (db == null)
                {
                    using (var db2 = CEMS_DHKH.Models.CEMS_DHKhoaHocContext.GetContext())
                        return GiangVienBanGiangDayDaiHoc(maGiangVien, ngayHoc, buoiHoc, db2);
                }
                else
                {
                    var ngayHoc0 = ngayHoc.Date;
                    var ngayHoc24 = ngayHoc.Date.Add(new TimeSpan(23, 59, 59));
                    var n = db.ThoiKhoaBieuDaoTaoDaiHocDbSet.Where(e =>
                        e.MaGiangVien == maGiangVien &&
                        ngayHoc0 <= e.NgayHoc && e.NgayHoc <= ngayHoc24 &&
                        e.BuoiHoc == buoiHoc).Count();
                    if (n > 0)
                        return true;
                    return false;
                }
            }
            catch (Exception exc)
            {
                throw new ThoiKhoaBieuDaiHocException("Không kiểm tra dữ liệu thời khoá biểu giảng dạy đại học được");
                //return false;
            }
        }

        internal static string GiangVienBanCongViec(string maGiangVien, DateTime ngayHoc, int buoiHoc, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GiangVienBanCongViec(maGiangVien, ngayHoc, buoiHoc, db2);
            else
            {
                var iThuTrongTuan = 1 << GetIndexFromDOW(ngayHoc.DayOfWeek);
                var iBuoiHoc = 1 << buoiHoc;
                // Lấy danh sách các mục công việc có chứa ngayHoc
                var lst = db.CongViecBanGiangVienDbSet.Where(e => e.MaGiangVien == maGiangVien && e.TuNgay <= ngayHoc && ngayHoc <= e.DenNgay).ToList();

                // Kiểm tra xung đột thứTrongTuần, buổiHọc
                foreach (var x in lst)
                {
                    if (x.TuNgay <= ngayHoc && ngayHoc <= x.DenNgay)
                        if ((x.ThuTrongTuan & iThuTrongTuan) > 0)
                            if ((x.Buoi & iBuoiHoc) > 0)
                                return x.NoiDungBan;
                }

                return null;
            }
        }

        internal static bool PhongHocBan(string maPhongHoc, DateTime ngayHoc, int buoiHoc, string ngoaiTruId = null, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return PhongHocBan(maPhongHoc, ngayHoc, buoiHoc, ngoaiTruId, db2);
            else
            {
                ngayHoc = ngayHoc.Date;

                // Kiểm tra lịch bận giảng dạy SĐH
                int n = db.LopHocPhan_ThoiKhoaBieuDbSet
                    .Where(e => e.MaPhongHoc == maPhongHoc && e.NgayHoc == ngayHoc && e.BuoiHoc == buoiHoc && e.MaLopHocPhan_ThoiKhoaBieuGUID != ngoaiTruId)
                    .Count();
                if (n > 0)
                    return true;

                // Kiểm tra lịch bận coi thi SĐH?

                // Kiểm tra lịch bận giảng dạy ĐH

                // ------------------------------
                return false;
            }
        }

        internal static bool LopHocPhanBan(string maLopHocPhanGUID, DateTime ngayHoc, int buoiHoc, string ngoaiTruId = null, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return LopHocPhanBan(maLopHocPhanGUID, ngayHoc, buoiHoc, ngoaiTruId, db2);
            else
            {
                ngayHoc = ngayHoc.Date;

                // Kiểm tra lịch bận giảng dạy SĐH
                int n = db.LopHocPhan_ThoiKhoaBieuDbSet
                    .Where(e => e.MaLopHocPhanGUID == maLopHocPhanGUID && e.NgayHoc == ngayHoc && e.BuoiHoc == buoiHoc && e.MaLopHocPhan_ThoiKhoaBieuGUID != ngoaiTruId)
                    .Count();
                if (n > 0)
                    return true;

                // Kiểm tra lịch bận coi thi SĐH?

                // Kiểm tra lịch bận giảng dạy ĐH

                // ------------------------------
                return false;
            }
        }

        internal static void InsertThoiKhoaBieu(LopHocPhan _LopHocPhan, 
            string maGiangVien, 
            string maGiangVienDaoTaoDaiHoc,
            string maPhongHoc, DateTime _NgayHoc, int _BuoiHoc, string moTa, bool kiemTraDuLieuDaiHoc, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    InsertThoiKhoaBieu(_LopHocPhan, maGiangVien, maGiangVienDaoTaoDaiHoc, maPhongHoc, _NgayHoc, _BuoiHoc, moTa, kiemTraDuLieuDaiHoc, db2);
            else
            {
                var id = System.Guid.NewGuid().ToString();

                string maLopHocPhan = _LopHocPhan.MaLopHocPhanGUID;

                // Kiểm tra để đảm bảo LHP không bận tại buổi học, ngày học này
                if (LopHocPhanBan(maLopHocPhan, _NgayHoc, _BuoiHoc, null, db))
                    throw new Exception("Lớp học phần bận tại thời điểm này");

                // Kiểm tra để đảm bảo GV không bận tại buổi học, ngày học này
                if (GiangVienBan(maGiangVien, _NgayHoc, _BuoiHoc, null, db))
                    throw new Exception("Giảng viên bận tại thời điểm này"); //"Giảng viên {0} bận tại buổi {1} ngày {2}", )

                // Kiểm tra để đảm bảo GV không bận giảng dạy ĐH tại buổi học, ngày học này
                if (kiemTraDuLieuDaiHoc)
                    if (GiangVienBanGiangDayDaiHoc(maGiangVienDaoTaoDaiHoc, _NgayHoc, _BuoiHoc))
                        throw new Exception("Giảng viên bận dạy ĐH tại thời điểm này");

                var congViec = GiangVienBanCongViec(maGiangVien, _NgayHoc, _BuoiHoc, db);
                if (congViec != null)
                    throw new Exception("Giảng viên bận " + congViec);

                // Kiểm tra để đảm bảo Phòng học không bận tại buổi học, ngày học này
                if (PhongHocBan(maPhongHoc, _NgayHoc, _BuoiHoc, null, db))
                    throw new Exception("Phòng học bận tại thời điểm này");

                // Thực hiện insert
                var x = new LopHocPhan_ThoiKhoaBieu()
                {
                    MaLopHocPhan_ThoiKhoaBieuGUID = id,
                    MaLopHocPhanGUID = maLopHocPhan,
                    MaGiangVien = maGiangVien,
                    MaPhongHoc = maPhongHoc,
                    NgayHoc = _NgayHoc.Date,
                    BuoiHoc = _BuoiHoc,
                    MoTa = moTa
                };
                db.LopHocPhan_ThoiKhoaBieuDbSet.Add(x);

                // Lưu dữ liệu
                BizNhatKyHoatDong.LogAndCommitInsert2(x, System.Guid.NewGuid().ToString(), LOAIDOITUONG.THỜI_KHOÁ_BIỂU_LỚP_HỌC_PHẦN, db);
            }
        }

        internal class ThoiKhoaBieuDaiHocException : Exception
        {
            public ThoiKhoaBieuDaiHocException(string msg, Exception exc = null) : base(msg, exc) { }
        }

        internal static void UpdateThoiKhoaBieu(string id, LopHocPhan _LopHocPhan, string maGiangVien, string maGiangVienDaoTaoDaiHoc, string maPhongHoc, DateTime _NgayHoc, int _BuoiHoc, string moTa, bool kiemTraDuLieuDaiHoc, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    UpdateThoiKhoaBieu(id, _LopHocPhan, maGiangVien, maGiangVienDaoTaoDaiHoc, maPhongHoc, _NgayHoc, _BuoiHoc, moTa, kiemTraDuLieuDaiHoc, db2);
            else
            {
                string maLopHocPhan = _LopHocPhan.MaLopHocPhanGUID;

                // Kiểm tra để đảm bảo GV không bận tại buổi học, ngày học này
                if (GiangVienBan(maGiangVien, _NgayHoc, _BuoiHoc, id, db))
                    throw new Exception("Giảng viên bận giảng dạy SĐH tại thời điểm này"); //"Giảng viên {0} bận tại buổi {1} ngày {2}", )

                if (kiemTraDuLieuDaiHoc)
                    if (GiangVienBanGiangDayDaiHoc(maGiangVienDaoTaoDaiHoc, _NgayHoc, _BuoiHoc))
                        throw new Exception("Giảng viên bận giảng dạy ĐH tại thời điểm này");

                var congViec = GiangVienBanCongViec(maGiangVien, _NgayHoc, _BuoiHoc, db);
                if (congViec != null)
                    throw new Exception("Giảng viên bận " + congViec);

                // Kiểm tra để đảm bảo Phòng học không bận tại buổi học, ngày học này
                if (PhongHocBan(maPhongHoc, _NgayHoc, _BuoiHoc, id, db))
                    throw new Exception("Phòng học bận tại thời điểm này");

                // Kiểm tra để đảm bảo LHP không bận tại buổi học, ngày học này
                if (LopHocPhanBan(maLopHocPhan, _NgayHoc, _BuoiHoc, id, db))
                    throw new Exception("Lớp học phần bận tại thời điểm này");

                // Thực hiện update
                var x = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaLopHocPhan_ThoiKhoaBieuGUID == id).FirstOrDefault();
                if (x == null)
                    throw new Exception("Mục thời khoá biểu không còn tồn tại trên hệ thống");
                var oldData = new LopHocPhan_ThoiKhoaBieu()
                {
                    MaLopHocPhan_ThoiKhoaBieuGUID = id,
                    MaLopHocPhanGUID = x.MaLopHocPhanGUID,
                    MaGiangVien = x.MaGiangVien,
                    MaPhongHoc = x.MaPhongHoc,
                    BuoiHoc = x.BuoiHoc,
                    NgayHoc = x.NgayHoc,
                    MoTa = x.MoTa
                };
                //x.MaLopHocPhan_ThoiKhoaBieuGUID = id;
                //x.MaLopHocPhanGUID = maLopHocPhan;
                x.MaGiangVien = maGiangVien;
                x.MaPhongHoc = maPhongHoc;
                x.NgayHoc = _NgayHoc.Date;
                x.BuoiHoc = _BuoiHoc;
                x.MoTa = moTa;

                // Lưu dữ liệu
                BizNhatKyHoatDong.LogAndCommitUpdate2(x, oldData, id, LOAIDOITUONG.THỜI_KHOÁ_BIỂU_LỚP_HỌC_PHẦN, db);
            }
        }

        internal static void DeleteThoiKhoaBieu(string id, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    DeleteThoiKhoaBieu(id, db2);
            else
            {
                var x = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaLopHocPhan_ThoiKhoaBieuGUID == id).FirstOrDefault();
                if (x == null)
                    throw new Exception("Mục thời khoá biểu không còn tồn tại trên hệ thống");
                db.LopHocPhan_ThoiKhoaBieuDbSet.Remove(x);
                BizNhatKyHoatDong.LogAndCommitDelete2(x, id, LOAIDOITUONG.THỜI_KHOÁ_BIỂU_LỚP_HỌC_PHẦN, db);
            }
        }

        internal static string[][] GetLichBanGiangVienPhongHoc(string maLopHocPhan, string maGiangVien, string maGiangVienDaoTaoDaiHoc, string maPhongHoc, DateTime tuNgay, DateTime denNgay, bool layDuLieuDaiHoc, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetLichBanGiangVienPhongHoc(maLopHocPhan, maGiangVien,maGiangVienDaoTaoDaiHoc, maPhongHoc, tuNgay, denNgay, layDuLieuDaiHoc, db2);
            else
            {
                tuNgay = tuNgay.Date;
                denNgay = denNgay.Date.Add(new TimeSpan(23, 59, 59));
                // gv bận và phòng bận có thể đến từ nhiều nguồn: SĐH, ĐH, coi thi SĐH
                // 1. Thời khoá biểu SĐH
                string[][] arr = new string[3][] { new string[7], new string[7], new string[7] };
                for (int i = 0; i < 3; i++)
                    for (int j = 0; j < 7; j++)
                        arr[i][j] = "";
                var lstLopBan = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaLopHocPhanGUID == maLopHocPhan &&
                    tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay).ToList();
                foreach (var x in lstLopBan)
                    arr[x.BuoiHoc][GetIndexFromDOW(x.NgayHoc.DayOfWeek)] += "*";

                var lstGiangVienBan = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaGiangVien == maGiangVien &&
                    tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay).ToList();
                foreach (var x in lstGiangVienBan)
                    arr[x.BuoiHoc][GetIndexFromDOW(x.NgayHoc.DayOfWeek)] += "☺";

                // 2. Thời khoá biểu ĐH
                if (layDuLieuDaiHoc)
                {
                    try
                    {
                        using (var db3 = CEMS_DHKH.Models.CEMS_DHKhoaHocContext.GetContext())
                        {
                            var lstGiangVienBanDH = db3.ThoiKhoaBieuDaoTaoDaiHocDbSet.Where(e => e.MaGiangVien == maGiangVienDaoTaoDaiHoc &&
                                tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay).ToList();
                            foreach (var x in lstGiangVienBanDH)
                                arr[x.BuoiHoc][GetIndexFromDOW(x.NgayHoc.DayOfWeek)] += "+";
                        }
                    }
                    catch (Exception exc)
                    {
                        throw new ThoiKhoaBieuDaiHocException("Không lấy dữ liệu giảng dạy đại học được", exc);
                    }
                }

                // 2'. Thời khoá biểu bận công việc
                var lstCongViecBan = db.CongViecBanGiangVienDbSet.Where(e =>
                    e.MaGiangVien == maGiangVien &&
                    ((e.TuNgay <= tuNgay && tuNgay <= e.DenNgay) ||
                    (tuNgay <= e.TuNgay && e.DenNgay <= denNgay) ||
                    (e.TuNgay <= denNgay && denNgay <= e.DenNgay))).ToList();


                for (int iThu = 0; iThu <= 6; iThu++)
                    for (int iBuoi = 0; iBuoi <= 2; iBuoi++)
                    {
                        var iThuTrongTuan = 1 << iThu;
                        var iBuoiHoc = 1 << iBuoi;
                        foreach (var x in lstCongViecBan)
                            if (x.TuNgay <= tuNgay.AddDays(iThu) && tuNgay.AddDays(iThu) <= x.DenNgay)
                                if ((x.ThuTrongTuan & iThuTrongTuan) > 0)
                                    if ((x.Buoi & iBuoiHoc) > 0)
                                        arr[iBuoi][iThu] += "/";
                    }

                var lstPhongBan = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaPhongHoc == maPhongHoc &&
                    tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay).ToList();
                foreach (var x in lstPhongBan)
                    arr[x.BuoiHoc][GetIndexFromDOW(x.NgayHoc.DayOfWeek)] += "⌂";


                // 3. Giảng viên bận theo khoảng thời gian đã đăng ký

                // ------------------------------
                return arr;
            }
        }

        //internal static string[][] GetLichBanGiangVienPhongHoc(string maGiangVien, string maPhongHoc, DateTime tuNgay, DateTime denNgay, CEMS4UG_DHKHContext db = null)
        //{
        //    if (db == null)
        //        using (var db2 = CEMS4UG_DHKHContext.GetContext())
        //            return GetLichBanGiangVienPhongHoc(maGiangVien, maPhongHoc, tuNgay, denNgay, db2);
        //    else
        //    {
        //        tuNgay = tuNgay.Date;
        //        denNgay = denNgay.Date;
        //        // gv bận và phòng bận có thể đến từ nhiều nguồn: SĐH, ĐH, coi thi SĐH
        //        // 1. Thời khoá biểu SĐH
        //        string[][] arr = new string[3][] { new string[7], new string[7], new string[7] };
        //        for (int i = 0; i < 3; i++)
        //            for (int j = 0; j < 7; j++)
        //                arr[i][j] = "";
        //        //var lstLopBan = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaLopHocPhanGUID == maLopHocPhan &&
        //        //    tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay).ToList();
        //        //foreach (var x in lstLopBan)
        //        //    arr[x.BuoiHoc][GetIndexFromDOW(x.NgayHoc.DayOfWeek)] += "*";

        //        var lstGiangVienBan = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaGiangVien == maGiangVien &&
        //            tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay).ToList();
        //        foreach (var x in lstGiangVienBan)
        //            arr[x.BuoiHoc][GetIndexFromDOW(x.NgayHoc.DayOfWeek)] += "☺";

        //        var lstPhongBan = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e => e.MaPhongHoc == maPhongHoc &&
        //            tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay).ToList();
        //        foreach (var x in lstPhongBan)
        //            arr[x.BuoiHoc][GetIndexFromDOW(x.NgayHoc.DayOfWeek)] += "⌂";

        //        // 2. Thời khoá biểu ĐH

        //        // ------------------------------
        //        return arr;
        //    }
        //}

        internal static int GetSoBuoiDaPhan(string maLopHocPhan, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetSoBuoiDaPhan(maLopHocPhan, db2);
            else
                return db.LopHocPhan_ThoiKhoaBieuDbSet.Count(e => e.MaLopHocPhanGUID == maLopHocPhan);
        }

        internal static object GetSoBuoiDaPhan(string maLopHocPhan, string maGiangVien, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetSoBuoiDaPhan(maLopHocPhan, maGiangVien, db2);
            else
                return db.LopHocPhan_ThoiKhoaBieuDbSet.Count(e => e.MaLopHocPhanGUID == maLopHocPhan && e.MaGiangVien == maGiangVien);
        }

        internal static int DeleteThoiKhoaBieu(LopHocPhan lopHocPhan, DateTime tuNgay, DateTime denNgay, CEMS4UG_DHKHContext db = null)
        {
            if (lopHocPhan == null)
                return -1;

            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return DeleteThoiKhoaBieu(lopHocPhan, tuNgay, denNgay, db2);
            else
            {
                var maLopHocPhan = lopHocPhan.MaLopHocPhanGUID;
                tuNgay = tuNgay.Date;
                denNgay = denNgay.Date.Add(new TimeSpan(23, 59, 59));
                var lst = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e =>
                    e.MaLopHocPhanGUID == maLopHocPhan &&
                    tuNgay <= e.NgayHoc && e.NgayHoc <= denNgay)
                    .ToList();
                if (lst.Count > 0)
                {
                    using (var trans = db.Database.BeginTransaction())
                    {
                        try
                        {
                            foreach (var x in lst)
                            {
                                db.LopHocPhan_ThoiKhoaBieuDbSet.Remove(x);
                                BizNhatKyHoatDong.LogAndCommitDelete2(x, x.MaLopHocPhan_ThoiKhoaBieuGUID, LOAIDOITUONG.THỜI_KHOÁ_BIỂU_LỚP_HỌC_PHẦN, db);
                            }
                            trans.Commit();
                        }
                        catch (Exception exc)
                        {
                            trans.Rollback();
                            throw exc;
                        }
                    }
                }
                return lst.Count;
            }
        }

        internal static int DeleteThoiKhoaBieu(LopHocPhan lopHocPhan, CEMS4UG_DHKHContext db = null)
        {
            if (lopHocPhan == null)
                return -1;
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return DeleteThoiKhoaBieu(lopHocPhan, db2);
            else
            {
                var maLopHocPhan = lopHocPhan.MaLopHocPhanGUID;
                var lst = db.LopHocPhan_ThoiKhoaBieuDbSet.Where(e =>
                    e.MaLopHocPhanGUID == maLopHocPhan)
                    .ToList();
                if (lst.Count > 0)
                {
                    using (var trans = db.Database.BeginTransaction())
                    {
                        try
                        {
                            foreach (var x in lst)
                            {
                                db.LopHocPhan_ThoiKhoaBieuDbSet.Remove(x);
                                BizNhatKyHoatDong.LogAndCommitDelete2(x, x.MaLopHocPhan_ThoiKhoaBieuGUID, LOAIDOITUONG.THỜI_KHOÁ_BIỂU_LỚP_HỌC_PHẦN, db);
                            }
                            trans.Commit();
                        }
                        catch (Exception exc)
                        {
                            trans.Rollback();
                            throw exc;
                        }
                    }
                }
                return lst.Count;
            }
        }

        internal static List<ThoiKhoaBieuForPrint> GetThoiKhoaBieuCacLHP(GiangVien cuaGiangVien, HocKy trongHocKy, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetThoiKhoaBieuCacLHP(cuaGiangVien, trongHocKy, db2);
            else
            {
                var maGiangVien = cuaGiangVien.MaGiangVien;
                var maHocKy = trongHocKy.MaHocKyGUID;
                var lst = db.LopHocPhan_ThoiKhoaBieuDbSet.Include("LopHocPhan").Include("GiangVien")
                    .Where(e => e.MaGiangVien == maGiangVien && e.LopHocPhan.MaHocKyGUID == maHocKy)
                    .OrderBy(e => e.LopHocPhan.TenLopHocPhan)
                    .ThenBy(e => e.NgayHoc)
                    .ThenBy(e => e.BuoiHoc)
                    .Select(e => new ThoiKhoaBieuForPrint()
                    {
                        MaLopHocPhanGUID = e.MaLopHocPhanGUID,
                        TenLopHocPhan = e.LopHocPhan.TenLopHocPhan,
                        MaHocPhanGUID = e.LopHocPhan.MaHocPhanGUID,
                        NgayHoc = e.NgayHoc,
                        BuoiHoc = e.BuoiHoc,
                        MaPhongHoc = e.MaPhongHoc,
                        MaGiangVien = e.MaGiangVien
                    })
                    .ToList();

                foreach (var x in lst)
                {
                    var date = x.NgayHoc;
                    x.NgayBatDau = date.Subtract(new TimeSpan(GetIndexFromDOW(date.DayOfWeek), 0, 0, 0)).Date;
                    x.NgayKetThuc = x.NgayBatDau.AddDays(6).Date;
                    x.ThoiGianApDung = string.Format("{0} ÷ {1}",
                        x.NgayBatDau.ToString("dd/MM/yyyy"), x.NgayKetThuc.ToString("dd/MM/yyyy"));
                    x.ThuTrongTuan = GetThuTrongTuanOf(date);
                    x.BuoiString = GetStringOfBuoi(x.BuoiHoc);
                }

                var iRow = 0;
                int nLopHocPhan = 0;
                while (iRow < lst.Count)
                {
                    lst[iRow].STT = (nLopHocPhan + 1).ToString();
                    nLopHocPhan++;

                    var hocPhan = BizHocPhan.GetByID(lst[iRow].MaHocPhanGUID);
                    if (hocPhan != null)
                        lst[iRow].SoTinChi = hocPhan.SoTinChi.ToString();

                    string maLopHocPhan = lst[iRow].MaLopHocPhanGUID;
                    var soHocVien = db.LopHocPhan_HocVienDbSet.Count(e => e.MaLopHocPhanGUID == maLopHocPhan);
                    lst[iRow].SoHocVien = soHocVien.ToString();

                    int i = iRow + 1;
                    while (true)
                    {
                        if (i >= lst.Count)
                            break;
                        if (lst[i].MaLopHocPhanGUID != maLopHocPhan)
                            break;
                        lst[i].TenLopHocPhan = "";
                        lst[i].STT = "";
                        i++;
                    }
                    var iRowStopOfLHP = i - 1;
                    // Lớp học phần: iRow -> iRowStopOfLHP

                    #region Gộp những dòng liên tiếp giống nhau NgayDauTuanCuaNgayHoc
                    var j = iRow;
                    while (j <= iRowStopOfLHP)
                    {
                        var ngayDauTuanCuaNgayHoc = lst[j].ThoiGianApDung;
                        var j2 = j + 1;
                        while (true)
                        {
                            if (j2 > iRowStopOfLHP)
                                break;
                            if (lst[j2].ThoiGianApDung != ngayDauTuanCuaNgayHoc)
                                break;
                            lst[j2].ThoiGianApDung = "";
                            j2++;
                        }
                        j = j2;
                    }
                    #endregion

                    #region Gộp những khối liên tiếp giống nhau Thứ+Buổi+Phòng
                    j = iRow;
                    while (j <= iRowStopOfLHP)
                    {
                        var thu7J = lst[j].NgayKetThuc;
                        var thuBuoiPhongJ = lst[j].ThuBuoiPhong;
                        int jj = j + 1;
                        while (jj <= iRowStopOfLHP && string.IsNullOrEmpty(lst[jj].ThoiGianApDung))
                        {
                            thuBuoiPhongJ += lst[jj].ThuBuoiPhong;
                            jj++;
                        }

                    KiemTraKhoi:
                        if (jj <= iRowStopOfLHP)
                        {
                            var thu7JJ = lst[jj].NgayKetThuc;
                            if (thu7J.AddDays(7) == thu7JJ)
                            {
                                var thuBuoiPhongJJ = lst[jj].ThuBuoiPhong;
                                int jj2 = jj + 1;
                                while (jj2 <= iRowStopOfLHP && string.IsNullOrEmpty(lst[jj2].ThoiGianApDung))
                                {
                                    thuBuoiPhongJJ += lst[jj2].ThuBuoiPhong;
                                    jj2++;
                                }
                                if (thuBuoiPhongJJ == thuBuoiPhongJ)
                                {
                                    thu7J = thu7JJ;
                                    lst[j].NgayKetThuc = thu7JJ;
                                    lst[j].ThoiGianApDung = string.Format("{0} ÷ {1}",
                                        lst[j].NgayBatDau.ToString("dd/MM/yyyy"), lst[j].NgayKetThuc.ToString("dd/MM/yyyy"));
                                    for (int k = jj; k < jj2; k++)
                                        lst[k].STT = "XXX";
                                    jj = jj2;
                                    goto KiemTraKhoi;
                                }
                                //else
                                //{
                                //    j = jj;
                                //}
                            }
                            j = jj;
                        }
                        else
                            break;
                    }
                    #endregion

                    iRow = iRowStopOfLHP + 1;
                }

                for (int i = lst.Count - 1; i >= 0; i--)
                    if (lst[i].STT == "XXX")
                        lst.RemoveAt(i);

                return lst;
            }
        }
    }
}
